package com.lzw.linspace.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.lzw.linspace.mapper.FileInfoMapper;
import com.lzw.linspace.mapper.Md5Mapper;
import com.lzw.linspace.po.FileInfoPO;
import com.lzw.linspace.po.Md5PO;
import com.lzw.linspace.service.UploadService;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.util.Date;
import java.util.List;


@Service
@Transactional
public class UploadImpl implements UploadService {

    private static final Logger LOGGER = LoggerFactory.getLogger(UploadImpl.class);

    private final static String PATH = "data";


    private FileInfoMapper fileInfoMapper;

    private Md5Mapper md5Mapper;

    @Autowired
    public void setFileInfoMapper(FileInfoMapper fileInfoMapper) {
        this.fileInfoMapper = fileInfoMapper;
    }

    @Autowired
    public void setMd5Mapper(Md5Mapper md5Mapper) {
        this.md5Mapper = md5Mapper;
    }

    @Override
    @SneakyThrows
    public void uploadSingleFile(MultipartFile mFile, String filePath) {
        if (isNotFilePathFormat(filePath)) throw new RuntimeException("文件路径格式不正常");

        byte[] fileBytes = mFile.getBytes();
        String md5 = DigestUtils.md5DigestAsHex(fileBytes);
        String filename = mFile.getOriginalFilename();
        String contentType = getContentTypeByFileFullName(filename);
        filename = getFileNameByFileFullName(filename);

        //检查是否存在md5
        if (md5Mapper.selectById(md5) == null) {
            //取md5第一个字符创建文件夹
            String p = PATH + File.separator + md5.charAt(0);
            File file = new File(p);
            if (!file.exists() && !file.isDirectory()) {
                boolean mkdirs = file.mkdirs();
                if (!mkdirs) LOGGER.error("文件夹创建失败！");
            }

            //写入文件
            File md5File = new File(p + File.separator + md5);
            FileOutputStream fop = new FileOutputStream(md5File);
            fop.write(fileBytes);
            fop.flush();
            fop.close();

            Md5PO md5PO = new Md5PO();
            md5PO.setMd5(md5);
            md5Mapper.insert(md5PO);
        }

        //检查文件夹是否已经保存了文件
        if (null != fileInfoMapper.selectOne(Wrappers.<FileInfoPO>query().lambda()
                .eq(FileInfoPO::getFilePath, filePath)
                .eq(FileInfoPO::getFileName, filename)
                .eq(contentType != null, FileInfoPO::getContentType, contentType)
                .eq(FileInfoPO::getDelFlag, 0))) {
            throw new RuntimeException("已存在相同文件名和类型的文件");
        } else {
            FileInfoPO fileInfoPO = new FileInfoPO();
            fileInfoPO.setFilePath(filePath);
            fileInfoPO.setFileName(filename);
            fileInfoPO.setContentType(contentType);
            fileInfoPO.setSize(mFile.getSize());
            fileInfoPO.setMd5(md5);
            fileInfoPO.setDelFlag(0);
            fileInfoPO.setCreateTime(new Date());

            fileInfoMapper.insert(fileInfoPO);
        }
    }

    @Override
    public void deleteSingleFileById(Long id) {
        UpdateWrapper<FileInfoPO> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(FileInfoPO::getId, id)
                .set(FileInfoPO::getDelFlag, 1);
        int update = fileInfoMapper.update(null, updateWrapper);
        if (update <= 0) {
            throw new RuntimeException("删除失败");
        }
    }

    @Override
    public void modifyFileNameById(Long id, String fileFullName) {
        UpdateWrapper<FileInfoPO> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(FileInfoPO::getId, id)
                .set(FileInfoPO::getFileName, getFileNameByFileFullName(fileFullName))
                .set(FileInfoPO::getContentType, getContentTypeByFileFullName(fileFullName))
                .set(FileInfoPO::getUpdateTime, new Date());
        int update = fileInfoMapper.update(null, updateWrapper);
        if (update <= 0) {
            throw new RuntimeException("修改失败");
        }
    }

    @Override
    public void modifyFilePathById(Long id, String filePath) {
        if (isNotFilePathFormat(filePath)) throw new RuntimeException("文件路径格式不正常");

        UpdateWrapper<FileInfoPO> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(FileInfoPO::getId, id)
                .set(FileInfoPO::getFilePath, filePath)
                .set(FileInfoPO::getUpdateTime, new Date());
        int update = fileInfoMapper.update(null, updateWrapper);
        if (update <= 0) {
            throw new RuntimeException("修改失败");
        }
    }

    @Override
    public List<FileInfoPO> listFileInfoPO(FileInfoPO fileInfoPO) {
        String filePath = fileInfoPO.getFilePath();
        fileInfoPO.setFilePath(null);
        QueryWrapper<FileInfoPO> queryWrapper = new QueryWrapper<>(fileInfoPO);
        queryWrapper.lambda().likeRight(!filePath.isBlank(), FileInfoPO::getFilePath, filePath);//路径根据左边的值匹配
        return fileInfoMapper.selectList(queryWrapper);
    }

    /**
     * 根据文件全名获取文件名
     *
     * @param fileFullName 文件全名
     * @return 文件名
     */
    private String getFileNameByFileFullName(String fileFullName) {
        if (fileFullName == null) return null;
        int index = fileFullName.lastIndexOf('.');
        return index < 0 ? fileFullName : fileFullName.substring(0, fileFullName.lastIndexOf('.'));
    }

    /**
     * 根据文件全名获取文件类型
     *
     * @param fileFullName 文件全名
     * @return 文件类型
     */
    private String getContentTypeByFileFullName(String fileFullName) {
        if (fileFullName == null) return null;
        int index = fileFullName.lastIndexOf('.');
        return index < 0 ? null : fileFullName.substring(index + 1);
    }

    /**
     * 是否不是文件路径格式,不是正确的格式返回true
     *
     * @param filePath 文件路径
     * @return boolean
     */
    private boolean isNotFilePathFormat(String filePath) {
        String[] split = filePath.split("/");
        for (String s : split) {
            if (s.isBlank()) return true;
        }
        return false;
    }
}
